package com.jcroke.DACGraph;

import java.io.BufferedWriter;
import java.lang.reflect.Constructor;
import java.util.ArrayList;

import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.jcroke.PC32.basetransform.Transformer;
import com.jcroke.PC32.datum.Datum;

/**
 * @author jcroke
 * 
 */

public class Pnode {
	public static final String BOLT = "bolt";
	public static final String NAME = "name";
	public static final String OUTPUTFIELD = "outputField";
	private RDFNode _rdfNode;
	private RDFNode _rdfName;
	private ArrayList<Signature> inputArgs = new ArrayList<Signature>();
	private ArrayList<Signature> outputArgs = new ArrayList<Signature>();
	private Logic logic;
	private BufferedWriter boWriter = null;

	public Pnode(QuerySolution qs) {
		this._rdfNode = qs.get(BOLT);
		this._rdfName = qs.get(NAME);
	}

	public Pnode(RDFNode bolt) {
		this._rdfNode = bolt;
	}

	public RDFNode getRDFNode() {
		return (_rdfNode);
	}

	public RDFNode getRDFName() {
		return (_rdfName);
	}

	public String getIRI() {
		return (_rdfNode.toString());
	}

	public String getNodeName() {
		return (substrIRI(getIRI()));
	}

	public void linkInput(Signature es) {
		inputArgs.add(es);
	}

	public void linkOutput(Signature es) {
		outputArgs.add(es);
	}

	public void linkLogic(Logic logic) {
		this.logic = logic;
	}

	public Logic getLogic() {
		return logic;
	}

	public ArrayList<Signature> getInputSignature() {
		return inputArgs;
	}

	public ArrayList<Signature> getOutputSignature() {
		return outputArgs;
	}

	public static String substrIRI(String iri) {
		String[] splits = iri.split("#");
		return (splits.length == 1 ? splits[0] : splits[1]);
	}

	public static String substrIRI(RDFNode iri) {
		if (iri == null) {
			System.out.println("iri was null");
		}
		String[] splits = iri.toString().split("#");
		return (splits.length == 1 ? splits[0] : splits[1]);
	}

	public Constructor<? extends Transformer> deriveLogicConstructor() {
		Constructor<? extends Transformer> c = null;

		if (getLogic().hasClass()) {
			try {
				try {
					c = Class
							.forName(
									Pnode.substrIRI(getLogic()
											.getSourceRDFClass()))
							.asSubclass(Transformer.class)
							.getDeclaredConstructor();
				} catch (SecurityException e) {
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		return c;

	}

	public Constructor<? extends Datum> deriveValueTypeConstructor() {
		Constructor<? extends Datum> c = null;
		if (getLogic().hasValue()) {
			try {
				c = Class
						.forName(
								Pnode.substrIRI(getOutputSignature().get(0)
										.getSourceTypeClass()))
						.asSubclass(Datum.class)
						.getDeclaredConstructor(String.class);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return c;
	}

	public String toDot(ArrayList<String> connections) {
		StringBuffer sb = new StringBuffer();
		StringBuffer nodeInputs = new StringBuffer();
		String rdfTag = Pnode.substrIRI(_rdfNode);
		rdfTag = rdfTag.replace("-", "_");

		StringBuffer nodeOutputs = new StringBuffer();

		String code = "";
		String value = "";
		if (logic.hasLinkedLogic()) {
			if (logic.hasCode()) {
				code = "Injected Code";
			} else if (logic.hasClass()) {
				code = Pnode.substrIRI(logic.getSourceRDFClass());

			}
		}
		if (logic.hasValue()) {
			value = Pnode.substrIRI(logic.getSourceRDFValue());
		}

		for (int i = 0; i < inputArgs.size(); i++) {
			String sp = inputArgs.get(i).getSourcePin();
			String lp = inputArgs.get(i).getLocalPin();

			String sPnode = Pnode.substrIRI(inputArgs.get(i).getSourcePnode());
			sPnode = sPnode.replace("-", "_");
			connections.add(rdfTag + ":" + lp + " -> " + sPnode + ":" + sp
					+ ";");
			nodeInputs.append("<" + lp + ">" + lp
					+ (i + 1 < inputArgs.size() ? "|" : ""));
		}

		for (int i = 0; i < outputArgs.size(); i++) {
			String sp = outputArgs.get(i).getSourcePin();
			nodeOutputs.append("<" + sp + ">" + sp
					+ (i + 1 < outputArgs.size() ? "|" : ""));
		}

		sb.append("\t\t");
		if (value.equals("")) {
			sb.append(rdfTag + " [label=\"{ {" + nodeInputs.toString()
					+ "} | { " + rdfTag + " } | { " + code + " } | {"
					+ nodeOutputs.toString() + "} }\"];\n");
		} else {
			sb.append(rdfTag + " [label=\"{ {" + nodeInputs.toString()
					+ "} | { " + rdfTag + " } | { " + code + " } | { " + value
					+ " } | {" + nodeOutputs.toString() + "} }\"];\n");
		}
		return (sb.toString());
	}

	public BufferedWriter getBoWriter() {
		return boWriter;
	}

	public void setBoWriter(BufferedWriter boWriter) {
		this.boWriter = boWriter;
	}
}